package com.leshan.lwm2m.client;

import com.leshan.lwm2m.instance.RandomTemperatureSensor;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.leshan.LwM2m;
import org.eclipse.leshan.client.californium.LeshanClient;
import org.eclipse.leshan.client.californium.LeshanClientBuilder;
import org.eclipse.leshan.client.object.Server;
import org.eclipse.leshan.client.resource.LwM2mObjectEnabler;
import org.eclipse.leshan.client.resource.ObjectsInitializer;
import org.eclipse.leshan.core.model.ObjectLoader;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.StaticModel;
import org.eclipse.leshan.core.request.BindingMode;
import org.eclipse.leshan.core.request.ContentFormat;
import org.springframework.stereotype.Component;

import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.List;

import static org.eclipse.leshan.LwM2mId.SECURITY;
import static org.eclipse.leshan.LwM2mId.SERVER;
import static org.eclipse.leshan.client.object.Security.*;
import static org.eclipse.leshan.client.object.Security.noSec;

/**
 * @author pengyu
 * @Date 2019/9/16
 * @Description
 */
@Component
public class ClientBuild {

    private final static String DEFAULT_ENDPOINT = "LeshanClientDemo";

    /**
     * 物体温度传感器
     */
    private static final int OBJECT_ID_TEMPERATURE_SENSOR = 3303;

    private final static String[] modelPaths = new String[] { "3303.xml" };

    public void initClient(){

        //创建端口节点
        String endpoint ;
        try {
            endpoint = InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            endpoint = DEFAULT_ENDPOINT;
        }
        // Get server URI
        String serverURI;
        serverURI = "coap://localhost:" + LwM2m.DEFAULT_COAP_PORT;


        //本地ip和端口
        String localAddress = "127.0.0.1";
        int localPort = 9091;

        //是否需要引导器
        boolean needBootstrap = false;

        // get PSK info
        byte[] pskIdentity = null;
        byte[] pskKey = null;

        // get RPK info
        PublicKey clientPublicKey = null;
        PrivateKey clientPrivateKey = null;
        PublicKey serverPublicKey = null;

        // get X509 info
        X509Certificate clientCertificate = null;
        X509Certificate serverCertificate = null;

        try {
            createAndStartClient(endpoint, localAddress, localPort, needBootstrap, serverURI, pskIdentity, pskKey,
                    clientPrivateKey, clientPublicKey, serverPublicKey, clientCertificate, serverCertificate);
        } catch (CertificateEncodingException e) {
            System.err.println("Unable to create and start client ...");
            e.printStackTrace();
            return;
        }

    }

    /**
     *
     * @param endpoint
     * @param localAddress
     * @param localPort
     * @param needBootstrap 是否需要bootstrap
     * @param serverURI  服务器url
     * @param pskIdentity
     * @param pskKey
     * @param clientPrivateKey  客户端私有密钥
     * @param clientPublicKey   客户端公有密钥
     * @param serverPublicKey   服务端公有密钥
     * @param clientCertificate 客户端证书
     * @param serverCertificate 服务器证书
     */
    public static void createAndStartClient(String endpoint, String localAddress, int localPort,
                                            boolean needBootstrap,String serverURI, byte[] pskIdentity,
                                            byte[] pskKey, PrivateKey clientPrivateKey, PublicKey clientPublicKey,
                                            PublicKey serverPublicKey, X509Certificate clientCertificate,
                                            X509Certificate serverCertificate) throws CertificateEncodingException {

        //Initialize model 初始化模型
        List<ObjectModel> models = ObjectLoader.loadDefault();
        //加载xml定义模型
        models.addAll(ObjectLoader.loadDdfResources("/models",modelPaths));

        //Initialize object list(初始化对象列表)
        ObjectsInitializer initializer =new ObjectsInitializer(new StaticModel(models));
        //是否需要引导
        if (needBootstrap) {
            if (pskIdentity != null) {
                initializer.setInstancesForObject(SECURITY, pskBootstrap(serverURI, pskIdentity, pskKey));
                initializer.setClassForObject(SERVER, Server.class);
            } else if (clientPublicKey != null) {
                initializer.setInstancesForObject(SECURITY, rpkBootstrap(serverURI, clientPublicKey.getEncoded(),
                        clientPrivateKey.getEncoded(), serverPublicKey.getEncoded()));
                initializer.setClassForObject(SERVER, Server.class);
            } else if (clientCertificate != null) {
                initializer.setInstancesForObject(SECURITY, x509Bootstrap(serverURI, clientCertificate.getEncoded(),
                        clientPrivateKey.getEncoded(), serverCertificate.getEncoded()));
                initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false));
            } else {
                initializer.setInstancesForObject(SECURITY, noSecBootstap(serverURI));
                initializer.setClassForObject(SERVER, Server.class);
            }
        } else {
            if (pskIdentity != null) {
                initializer.setInstancesForObject(SECURITY, psk(serverURI, 123, pskIdentity, pskKey));
                initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false));
            } else if (clientPublicKey != null) {
                initializer.setInstancesForObject(SECURITY, rpk(serverURI, 123, clientPublicKey.getEncoded(),
                        clientPrivateKey.getEncoded(), serverPublicKey.getEncoded()));
                initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false));
            } else if (clientCertificate != null) {
                initializer.setInstancesForObject(SECURITY, x509(serverURI, 123, clientCertificate.getEncoded(),
                        clientPrivateKey.getEncoded(), serverCertificate.getEncoded()));
                initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false));
            } else {
                //创建一个不需要安全的SECURITY对象以及一个SERVER对象
                initializer.setInstancesForObject(SECURITY, noSec(serverURI, 123));
                initializer.setDefaultContentFormat(SECURITY, ContentFormat.JSON);

                initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false));
                initializer.setDefaultContentFormat(SERVER, ContentFormat.JSON);
            }
        }
        //将自定义的对象加入对象列表
        initializer.setInstancesForObject(OBJECT_ID_TEMPERATURE_SENSOR,new RandomTemperatureSensor());
        //定义内容格式
        initializer.setDefaultContentFormat(OBJECT_ID_TEMPERATURE_SENSOR, ContentFormat.JSON);

        //创建对象启用程序(暂时不明白作用)
        List<LwM2mObjectEnabler> enablers = initializer.createAll();

        //Create CoAP Config
        NetworkConfig coapConfig;
        File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME);
        if (configFile.isFile()) {
            coapConfig = new NetworkConfig();
            coapConfig.load(configFile);
        } else {
            coapConfig = LeshanClientBuilder.createDefaultNetworkConfig();
            coapConfig.store(configFile);
        }
        //创建LeshanClient构建者
        LeshanClientBuilder builder = new LeshanClientBuilder(endpoint);
        builder.setLocalAddress(localAddress,localPort);
        builder.setCoapConfig(coapConfig);
        builder.setObjects(enablers);
        //构建LeshanClient
        LeshanClient client = builder.build();

        // Start the client 开启client(会自动想服务器注册)
        client.start();




    }



}
